#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "EventLoop.h"
#include "TcpConnection.h"
#include "Log.h"

struct EventLoop *eventLoopInitEx(char *threadName, enum EventLoopModelType type);

int taskWakeup(struct EventLoop *evLoop) // 写数据
{
    const char *msg = "加油加油加油";
    write(evLoop->socketPair[0], msg, strlen(msg));
    return 0;
}
int readLocalMessage(void *arg) // 读数据
{
    struct EventLoop *evLoop = (struct EventLoop *)arg;
    char buff[50] = {0};
    read(evLoop->socketPair[1], buff, sizeof(buff));
    return 0;
}

struct EventLoop *eventLoopInit(enum EventLoopModelType type)
{
    return eventLoopInitEx(NULL, type);
}

struct EventLoop *eventLoopInitEx(char *threadName, enum EventLoopModelType type)
{
    struct EventLoop *evLoop = (struct EventLoop *)malloc(sizeof(struct EventLoop));
    if (evLoop == NULL)
    {
        perror("malloc error");
        return NULL;
    }
    evLoop->isRun = false;
    evLoop->threadID = pthread_self();
    pthread_mutex_init(&evLoop->mutex, NULL);
    evLoop->threadName = (threadName == NULL) ? "MainThread" : threadName;
    switch (type)
    {
    case EPOLL:
        evLoop->dispatcher = &EpollDispatcher;
        break;
    case POLL:
        evLoop->dispatcher = &PollDispatcher;
        break;
    default:
        evLoop->dispatcher = &SelectDispatcher;
        break;
    }
    evLoop->dispatcherData = evLoop->dispatcher->init();
    // 链表
    evLoop->head = evLoop->tail = NULL;
    // map
    evLoop->channelMap = channelMapInit(128);

    int32_t ret = socketpair(AF_UNIX, SOCK_STREAM, 0, evLoop->socketPair);
    if (ret == -1)
    {
        perror("socketpair error");
        exit(0);
    }
    // 指定规则:evLoop->socketPair[0]发送数据    evLoop->socketPair[1]接收数据
    struct Channel *channel = channelInit(evLoop->socketPair[1], ReadEvent, readLocalMessage, NULL, NULL, evLoop);
    // 添加到任务队列
    eventLoopAddTask(evLoop, channel, ADD);
    return evLoop;
}

int8_t eventLoopRun(struct EventLoop *evLoop)
{
    assert(evLoop != NULL);
    // 取出事件分发和检测模型
    struct Dispatcher *dispatcher = evLoop->dispatcher;
    // 比较线程ID是否正常
    if (evLoop->threadID != pthread_self())
    {
        perror("evLoop->threadID != pthread_self");
        return -1;
    }
    evLoop->isRun = true;
    while (evLoop->isRun)
    {   
        dispatcher->dispatch(evLoop, 2); //2s
        evebtLoopProcessTask(evLoop);
    }
    return 0;
}

int8_t eventActivate(struct EventLoop *evLoop, int32_t fd, int32_t event)
{
    if (evLoop == NULL || fd < 0)
    {
        return -1;
    }
    // 取出channel
    struct Channel *channel = evLoop->channelMap->list[fd];
    assert(channel->fd == fd);
    if (event & WriteEvent && channel->writeCallback)
    {
        channel->writeCallback(channel->arg);
    }
    if (event & ReadEvent && channel->readCallback)
    {
        channel->readCallback(channel->arg);
    }
    return 0;
}

int8_t eventLoopAddTask(struct EventLoop *evLoop, struct Channel *channel, enum ElemType type)
{
    // 加锁 保护共享资源
    pthread_mutex_lock(&evLoop->mutex);

    // 创建新节点
    struct ChannelElement *node = (struct ChannelElement *)malloc(sizeof(struct ChannelElement));
    node->channel = channel;
    node->type = type;
    node->next = NULL;
    if (evLoop->head == NULL)
    {
        evLoop->head = evLoop->tail = node;
    }
    else
    {
        evLoop->tail->next = node;
        evLoop->tail = node;
    }
    pthread_mutex_unlock(&evLoop->mutex);

    if (evLoop->threadID == pthread_self())
    {
        // 子线程/主线程
        evebtLoopProcessTask(evLoop);
    }
    else
    {
        // 主线程 -- 告诉子线程处理任务队列中的任务
        // 1.子线程在工作 2.子线程被阻塞了：select poll epoll(极大概率)
        printf("主线程通过cfd = %d 唤醒子线程\n", evLoop->socketPair[1]);
        taskWakeup(evLoop);
    }

    return 0;
}

int8_t evebtLoopProcessTask(struct EventLoop *evLoop)
{
    pthread_mutex_lock(&evLoop->mutex);
    while (evLoop->head != NULL)
    {
        struct ChannelElement *task = evLoop->head;
        evLoop->head = evLoop->head->next;

        switch (task->type)
        {
        case ADD:
            if (eventLoopAdd(evLoop, task->channel) == -1)
            {
                return -1;
            }
            break;
        case DELECT:
            if (eventLoopRemove(evLoop, task->channel) == -1)
            {
                return -1;
            }
            break;
        case MODIFY:
            if (eventLoopModify(evLoop, task->channel) == -1)
            {
                return -1;
            }
            break;
        }
        free(task);
    }
    evLoop->head = evLoop->tail = NULL;
    pthread_mutex_unlock(&evLoop->mutex);

    return 0;
}

int8_t eventLoopAdd(struct EventLoop *evLoop, struct Channel *channel)
{
    int32_t fd = channel->fd;
    ChannelMap *channelMap = evLoop->channelMap;
    if (fd >= channelMap->size)
    {
        // 没有足够的空间存储键值对 fd-channel >> 扩容
        if (!MakeMapRoom(channelMap, fd, sizeof(struct channel *)))
        {
            return -1;
        }
    }
    // 找到fd对应的数组元素位置，并存储
    if (channelMap->list[fd] == NULL)
    {
        channelMap->list[fd] = channel;
        evLoop->dispatcher->add(channel, evLoop);
    }
    return 0;
}

int8_t eventLoopRemove(struct EventLoop *evLoop, struct Channel *channel)
{
    int32_t fd = channel->fd;
    ChannelMap *channelMap = evLoop->channelMap;
    if (fd >= channelMap->size)
    {
        return -1;
    }
    int32_t ret = evLoop->dispatcher->remove(channel, evLoop);
    if(ret == 0)
    {
        channelMap->list[fd] = NULL;
    }
    return ret;
}

int8_t eventLoopModify(struct EventLoop *evLoop, struct Channel *channel)
{
    int32_t fd = channel->fd;
    ChannelMap *channelMap = evLoop->channelMap;
    if (fd >= channelMap->size)
    {
        return -1;
    }
    int32_t ret = evLoop->dispatcher->modify(channel, evLoop);
    return ret;
}

int8_t destroyChannel(struct EventLoop *evLoop, struct Channel *channel)
{
    if (evLoop->channelMap->list[channel->fd] == NULL)
    {
        return -1;
    }
    else
    {
        evLoop->channelMap->list[channel->fd] == NULL;
        // 关闭 fd
        close(channel->fd);
        // 释放 channel
        free(channel);
    }
    return 0;
}
